﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace System
{
    /// <summary>
    /// 面向切面编程辅助
    /// </summary>
    public static class AOPHelper
    {
        /// <summary>
        /// 调用指定的函数，如果为函数指定了<see cref="AOPMethodAttribute"/>特性，则可以对函数的运行进行跟踪控制。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="methodname">函数名</param>
        /// <param name="paras">参数</param>
        /// <returns></returns>
        public static object AOPMethodRun(this object obj, string methodname, params object[] paras)
        {
            var type = obj.GetType();
            var mi = type.GetMethod(methodname);
            if (mi == null)
            {
                throw new MissingMethodException(type.FullName, methodname);
            }
            var ama = mi.GetCustomAttribute<AOPMethodAttribute>(true);
            object result = null;
            if (ama != null)
            {
                ama.ContextInstance = obj;
                ama.ContextMethodInfo = mi;
                ama.ContextType = type;
                ama.BeforeRuning();
                if (!ama.aborted)
                {
                    result = ama.RunMethod(paras);
                    ama.AfterRun();
                }
                else
                {
                    result = mi.Invoke(obj, paras);
                }

            }
            return result;
        }
    }

    public class AOPAttribute : Attribute
    {
        /// <summary>
        /// AOP上下文中的类型
        /// </summary>
        public Type ContextType { get; internal set; }
        /// <summary>
        /// AOP上下文实例
        /// </summary>
        public object ContextInstance { get;internal set; }


    }
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class AOPMethodAttribute : AOPAttribute
    {
        /// <summary>
        /// 方法信息
        /// </summary>
        public MethodInfo ContextMethodInfo { get;internal set; }

        internal bool aborted = false;
        protected internal virtual void BeforeRuning()
        {

        }
        protected internal virtual object RunMethod(params object[] paras)
        {
            return ContextMethodInfo.Invoke(ContextInstance, paras);
        }

        /// <summary>
        /// 终止函数的执行，在<see cref="BeforeRuning"/>中使用可以终止继续执行函数。
        /// </summary>
        protected void Abort()
        {
            aborted = true;
        }
        protected internal virtual void AfterRun()
        {

        }
    }
}
